package uform.model.value;

import uform.model.core.IValueHandler;
import thx.util.Result;
import uform.model.core.Filters;
using Types;
import uform.model.core.Crawler;
import thx.validation.IValidator;

class ValueType<T> implements IValueHandler<T>
{
	public var valueFilters(default, null) : Filters<T>;
	public var validators(default, null) : Array<IValidator<T>>;
	public var meta(default, null) : Hash<Dynamic>;
	
	private function new()
	{
		valueFilters = new Filters();
		validators = [];
		meta = new Hash();
	}
	
	public function validateType(value : Dynamic) : Result
	{
		return Result.Ok;
	}
	
	public function validate(value : Dynamic) : Result
	{
		switch(validateType(value))
		{
			case Ok:
				return validateValue(value);
			case Failure(e):
				return Result.Failure(e);
		}
	}
	
	public function validateValue(value : T) : Result
	{
		for (validator in validators)
		{
			var result = validator.validate(value);
			switch(result)
			{
				case Failure(_): return result;
				default: //
			}
		}
		return Ok;
	}
	
	function _parse(value : String, ?ref : { s : String }) : T
	{
		return throw "abstract method '" + this.fullName() + '._parse()';
	}
	
	public function filter(value : T) : T
	{
		return valueFilters.filter(value);
	}
	
	public function parse(value : String, ?ref : { s : String }) : T
	{
		var result = _parse(value, ref);
		return filter(result);
	}
	
	public function render(value : T) : String
	{
		return "" + value;
	}
	
	public function toString()
	{
		return this.className() + (validators.length > 0 ? " " + validators.toString() : "");
	}
	
	public function resolve(crawler : Crawler)
	{
		
	}
	
	public function addValidator(validator : IValidator<T>)
	{
		validators.push(validator);
		return this;
	}
	
	public function addMeta(key : String, value : Dynamic)
	{
		meta.set(key, value);
		return this;
	}
}